/*******************************************************************************
 * Copyright (c) 2008 Sylvain Sicard.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Fabienne Boyer - initial API and implementation
 ******************************************************************************/
package fr.jade.reflex.control.binding;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.Interface;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.control.IllegalBindingException;
import org.objectweb.fractal.api.control.IllegalLifeCycleException;
import org.objectweb.fractal.api.control.LifeCycleController;
import org.objectweb.fractal.api.factory.InstantiationException;

import fr.jade.fraclite.InitializationContext;
import fr.jade.fraclite.control.binding.BasicBindingController;
import fr.jade.reflex.api.control.BindingNotificationController;
import fr.jade.reflex.api.control.ReflexController;
import fr.jade.reflex.util.Reflex;
import fr.jade.util.log.Logger;
import fr.jade.util.log.config.LogReflex;

/**
 * Provides an implementation of the
 * {@link org.objectweb.fractal.api.control.BindingController} interface which
 * manages the causal connection with the dual level (i.e meta/execution) : any
 * binding operation performed on the current component is notified to the
 * binding controller of dual component.
 * 
 * @author Fabienne Boyer 18/05/05
 * @author Sylvain Sicard
 * @contact Fabienne.Boyer@inrialpes.fr
 */

public class ReflexBindingController extends BasicBindingController implements BindingNotificationController {
  /**
   * The <tt>weaveableRC</tt> field required by this mixin. This field is
   * supposed to reference the {@link ReflexController} interface of the
   * component to which this controller object belongs.
   */

  public ReflexController weaveableRC;
    
    /**
     * Initializes the fields of this mixin and then calls the overriden method.
     *
     * @param ic information about the component to which this controller object
     *      belongs.
     * @throws InstantiationException if the initialization fails.
     */

    public void initFcController (final InitializationContext ic) throws InstantiationException {
      Logger.println(LogReflex.debug, "ReflexBindingMixin : init");
      weaveableRC = (ReflexController) ic.getInterface("reflex-controller");
      super.initFcController(ic);
    }
    
    protected BindingNotificationController getDualCtrl() {
      assert weaveableRC != null : "Component must have a ReflexController";
      Component dual = weaveableRC.getCmpRef();
      assert dual != null : "Component must have a dual";
      BindingNotificationController dualCtrl = null;
      try {
        dualCtrl = Reflex.getBindingNotificationController(dual);
      } catch (NoSuchInterfaceException ignored) {    }
      assert dualCtrl != null : "Dual component must have a GenericAttributeNotificationController";
      return dualCtrl;
    }
    
    private String myName(){
      String level = weaveableRC.getLevel();
      String ctrlDesc = weaveableRC.getReflexAttribute("controllerDesc");
      String infos = "[" + level + "/" + ctrlDesc + "]";
//      try{
//        return FractalNavigator.getNameController(weaveableC).getFcName() + infos;
//      }catch(Exception e){
        return "unammed component" + infos;
//      }
    }
    
    // -------------------------------------------------------------------------
    // Fields and methods added and overriden by the mixin class
    // -------------------------------------------------------------------------

    /**
     * Calls the overriden bindFc method and then notifies the dual level of the
     * binding.
     * 
     * @param clientItfName
     *            the name of a client interface of the component to which this
     *            interface belongs.
     * @param serverItf
     *            a server interface.
     * @throws NoSuchInterfaceException
     *             if there is no such client interface.
     * @throws IllegalBindingException
     *             if the binding cannot be created.
     * @throws IllegalLifeCycleException
     *             if this component has a {@link LifeCycleController}
     *             interface, but it is not in an appropriate state to perform
     *             this operation.
     */

    public void bindFc(String clientItfName, Object serverItf) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {
      bindFcNotification(clientItfName, serverItf);
      getDualCtrl().bindFcNotification(clientItfName, Reflex.getDualInterface((Interface) serverItf));
    }

    /**
     * Calls the overriden bindFc method.
     * 
     * @param clientItfName
     *            the name of a client interface of the component to which this
     *            interface belongs.
     * @param serverItf
     *            a server interface.
     * @throws NoSuchInterfaceException
     *             if there is no such client interface.
     * @throws IllegalBindingException
     *             if the binding cannot be created.
     * @throws IllegalLifeCycleException
     *             if this component has a {@link LifeCycleController}
     *             interface, but it is not in an appropriate state to perform
     *             this operation.
     */
    public void bindFcNotification(String clientItfName, Object serverItf) throws NoSuchInterfaceException, IllegalBindingException,IllegalLifeCycleException {

        Logger.println(LogReflex.info, "ReflexBindingMixin.bindFcNotification " + clientItfName);
        Logger.println(LogReflex.debug, myName());
        
        // calls the overriden bindFc method
        super.bindFc(clientItfName, serverItf);
    }

    /**
     * Calls the overriden method and then notifies the dual level of the
     * unbinding.
     * 
     * @param clientItfName
     *            the name of a client interface of the component to which this
     *            interface belongs.
     * @throws NoSuchInterfaceException
     *             if there is no such client interface.
     * @throws IllegalBindingException
     *             if the binding cannot be removed.
     * @throws IllegalLifeCycleException
     *             if this component has a {@link LifeCycleController}
     *             interface, but it is not in an appropriate state to perform
     *             this operation.
     */
    public void unbindFc(String clientItfName) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {
      unbindFcNotification(clientItfName);
      getDualCtrl().unbindFcNotification(clientItfName);
    }

    /**
     * Calls the overriden unbindFc method.
     * 
     * @param clientItfName
     *            the name of a client interface of the component to which this
     *            interface belongs.
     * @throws NoSuchInterfaceException
     *             if there is no such client interface.
     * @throws IllegalBindingException
     *             if the binding cannot be removed.
     * @throws IllegalLifeCycleException
     *             if this component has a {@link LifeCycleController}
     *             interface, but it is not in an appropriate state to perform
     *             this operation.
     */
    public void unbindFcNotification(String clientItfName) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {

        Logger.println(LogReflex.info, "ReflexBindingMixin.unbindFcNotification " + clientItfName);
        Logger.println(LogReflex.debug, myName());
        
        // calls the overriden unbindFc method
        super.unbindFc(clientItfName);
    }

}
